package com.songhq.data.log;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.slf4j.Logger;
import org.springframework.core.env.Environment;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.alibaba.fastjson.JSON;
import com.songhq.data.log.util.ExceptionUtil;
import com.songhq.data.log.util.LogUtil;
import com.songhq.data.log.util.MLogFactory;

public abstract class BaseLoggingAspect
{
  final Environment env;
  private static Logger log_call = MLogFactory.getLog("LOG_CALL_INFO");

  public BaseLoggingAspect(Environment env)
  {
    this.env = env;
  }

  public abstract void remoteCallPointcut();

  public abstract Object logAround(ProceedingJoinPoint paramProceedingJoinPoint)
    throws Throwable;

  public abstract void afterThrowing(JoinPoint paramJoinPoint, Throwable paramThrowable)
    throws Throwable;

  public Object remoteLogAround(ProceedingJoinPoint joinPoint, String systemId)
    throws Throwable
  {
    return printLog(joinPoint, systemId);
  }

  private Object printLog(ProceedingJoinPoint joinPoint, String systemId) throws Throwable
  {
    try {
      long begin = System.currentTimeMillis();
      Object result = joinPoint.proceed();
      long end = System.currentTimeMillis();
      long useTime = end - begin;
      setUseTime(useTime);
      String resultStr = getString(result, systemId);
      String logString = String.format("%s|%s|^%s^%s^%s", new Object[] { LogUtil.commonHeaders(printInvokedMethod(joinPoint), useTime), systemId, printArgs(joinPoint), resultStr, getBussId() });
      if ((null != logString) && (!"".equals(logString)))
        log_call.info(logString);
      else {
        LogUtil.error("printLog() logString is null", systemId);
      }
      return result;
    }
    catch (Exception e)
    {
      LogUtil.error(e, printInvokedMethod(joinPoint));
      throw e;
    }
  }

  public String getBussId()
  {
    try {
      if (null != RequestContextHolder.getRequestAttributes()) {
        HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
        return LogUtil.getString(request.getHeader("BUSS_ID"));
      }

      return "";
    } catch (Exception e) {
    }
    return "";
  }

  public String getString(Object result, String systemId)
  {
    String resultStr = "";
    try {
      if (null == result) {
        return resultStr;
      }
      String str = JSON.toJSONString(result);
      if ((null == str) || ("".equals(str))) {
        return resultStr;
      }

      if ((systemId.contains("playurl")) || (systemId.contains("user"))) {
        return str;
      }

      int bodyLength = str.length();
      int endIndex = 2000;
      if (bodyLength < endIndex) {
        endIndex = bodyLength;
      }
      resultStr = str.substring(0, endIndex);
    } catch (Exception e) {
      LogUtil.error(e, "BaseLoggingAspect.getString");
    }
    return resultStr;
  }

  public void remoteLogAfterThrowing(JoinPoint joinPoint, Throwable ex)
    throws Throwable
  {
    LogUtil.error(ExceptionUtil.getMessage(ex), printInvokedMethod(joinPoint));
  }

  protected String printInvokedMethod(JoinPoint joinPoint)
  {
    Logger log = MLogFactory.getLog();
    String name = "";
    try {
      if (joinPoint == null) {
        return "";
      }
      String classType = joinPoint.getTarget().getClass().getName();
      Class clazz = Class.forName(classType);
      String clazzName = clazz.getName();
      String methodName = joinPoint.getSignature().getName();
      name = clazzName + "." + methodName;
    } catch (ClassNotFoundException e) {
      log.error(e.getMessage(), e);
    }
    return name;
  }

  private String printArgs(JoinPoint jp)
  {
    StringBuilder argsStr = new StringBuilder();
    if (jp != null) {
      Object[] arguments = jp.getArgs();
      if (arguments != null) {
        for (Object arg : arguments) {
          if (arg == null)
            argsStr.append("$");
          else {
            argsStr.append("$").append(arg);
          }
        }
      }
    }
    return argsStr.toString();
  }

  private void setUseTime(long useTime)
  {
    if (null != RequestContextHolder.getRequestAttributes())
      try {
        HttpServletResponse response = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getResponse();
        if (!response.containsHeader("P_USETIME"))
          response.addHeader("P_USETIME", useTime + "");
      }
      catch (Exception e) {
        e.printStackTrace();
      }
  }
}